package com.soul.server.server;

import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.soul.autoconfig.template.FaceTemplate;
import com.soul.autoconfig.template.HuanXinTemplate;
import com.soul.autoconfig.template.OssTemplate;
import com.soul.autoconfig.template.SmsTemplate;
import com.soul.commons.constans.Constants;
import com.soul.commons.exception.SoulGlobalException;
import com.soul.commons.utils.JwtUtils;
import com.soul.dubbo.api.db.UserApi;
import com.soul.dubbo.api.db.UserInfoApi;
import com.soul.model.db.User;
import com.soul.model.db.UserInfo;
import com.soul.model.vo.ErrorResult;
import com.soul.model.vo.UserInfoVo;
import com.soul.server.utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.joda.time.DateTime;
import org.joda.time.Years;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author mdoya
 * @version 1.0
 * @description: User业务层
 */
@Slf4j
@Service
public class UserService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private SmsTemplate smsTemplate;

    @DubboReference
    private UserApi userApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @Autowired
    private OssTemplate ossTemplate;

    @Autowired
    private FaceTemplate faceTemplate;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    /**
     * 发送手机短信  不管手机号码是否存在都要发送   没有注册则默认自动注册
     *
     * @param phone 手机号码
     */
    public void sendCode(String phone) {
        log.info("手机号码{}", phone);
        String redisKey = "VALIDATE_CODE_" + phone;
        // 1. 校验手机号码
        if (StringUtils.isEmpty(phone)) throw new SoulGlobalException("请输入正确手机号码!");

        // 2. 获取redis中验证码 存在
        String redisCode = redisTemplate.opsForValue().get(redisKey);
//        redisTemplate.boundValueOps(redisKey); // 同等于opsForValue().get();  但是boundValueOps支持链式编程
        if (StringUtils.isNotEmpty(redisCode)) throw new SoulGlobalException(ErrorResult.duplicate());

        // 3. 获取redis中验证码 不存在 生成验证码
//        String randomCode = RandomStringUtils.randomNumeric(6);
        String randomCode = "666666";
        // 4. 发送验证码
        if (false) smsTemplate.sendSms(phone, randomCode); // 开发阶段

        // 5. 验证码存在redis中设置有效时间
        redisTemplate.opsForValue().set(redisKey, randomCode, 3, TimeUnit.MINUTES);
        log.info("手机号码:{}  获取验证码成功{}", phone, randomCode);
        System.err.println("验证码：" + randomCode);
    }

    /**
     * 用户登录(自动注册、老用户登录)
     *
     * @param phone            手机号码
     * @param verificationCode 验证码
     * @return
     */
    public Map login(String phone, String verificationCode) {
        // redis中验证码的key
        String redisKey = "VALIDATE_CODE_" + phone;
        boolean isNew = false;
        // 1. 获取redis中
        String redisCode = redisTemplate.opsForValue().get(redisKey);
        // 校验验证码
        if (StringUtils.isEmpty(verificationCode)) {
            throw new SoulGlobalException("验证码失效，请获取验证码!");
        }
        // 校验前端code和redis中code是否一致
        if (!verificationCode.equals(redisCode)) {
            throw new SoulGlobalException("验证码不一致!");
        }
        // 查询用户
        User user = userApi.findByMobile(phone);
        if (user == null) {
            user = new User();
            user.setMobile(phone);
            String substring = phone.substring(6);
            user.setPassword(SecureUtil.md5(substring)); // md5加密
            isNew = true;
            Long userId = userApi.add(user); // 自动注册用户
            user.setId(userId);

            // 添加环信即时通讯账号
            user.setHxUser(Constants.HX_USER_PREFIX+user.getId());
            user.setPassword(Constants.INIT_PASSWORD);
            Boolean result = huanXinTemplate.createUser(user.getHxUser(), user.getHxPassword());
            if (result){
                userApi.updateById(user);
            }
        }
        // 生成token字符串  base64位
        String token = JwtUtils.createToken(user.getId(), phone);
        // token对象保存到redis中
        redisTemplate.opsForValue().set("TOKEN_" + token, JSON.toJSONString(user), 30, TimeUnit.MINUTES);
        // 封装数据返回
        Map map = new HashMap<>();
        map.put("token", token);
        map.put("isNew", isNew);
        return map;
    }

    /**
     *  首次登录---完善资料
     * @param userInfoVo 接受前端对象
     */
    public void loginReginfo(UserInfoVo userInfoVo) {
        UserInfo userInfo = new UserInfo();
        BeanUtils.copyProperties(userInfoVo,userInfo);
        userInfo.setId(UserHolder.getUser().getId());
        userInfo.setAge(getAge(userInfoVo.getBirthday()));
        userInfoApi.add(userInfo);
    }

    /**
     *  首次登录---补充头像
     * @param headPhoto
     */
    public void loginReginfoHeader(MultipartFile headPhoto) {
        try {
            // 原有图片名称
            String filename = headPhoto.getOriginalFilename();
            // 人脸识别
            if (!faceTemplate.detect(headPhoto.getBytes())){
                throw new SoulGlobalException(ErrorResult.faceError());
            }
            // oss对象存储服务
            String avatarUrl = ossTemplate.upload(filename, headPhoto.getInputStream());
            // 删除原有头像
            if (StringUtils.isNotEmpty(avatarUrl)){
                UserInfoVo userInfoVo = userInfoApi.findIdUser(UserHolder.getUser().getId());
                String avatar = userInfoVo.getAvatar();
                System.err.println("删除原有avatar图片 = " + avatar);
                ossTemplate.deleteOssFile(avatar);
            }

            // 更新头像
            UserInfo userInfo = new UserInfo();
            userInfo.setId(UserHolder.getUser().getId());
            userInfo.setAvatar(avatarUrl);
            userInfoApi.updateUserId(userInfo);
        } catch (IOException e) {
            throw new SoulGlobalException(ErrorResult.error());
        }

    }

    /**
     * 通过年-月-日获取年龄
     * @param yearMonthDay
     * @return
     */
    private int getAge(String yearMonthDay){
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date birthDay = sdf.parse(yearMonthDay);
            Years years = Years.yearsBetween(new DateTime(birthDay), DateTime.now());
            return years.getYears();
        } catch (ParseException e) {
            log.error("获取用户年龄失败!", e);
            return 0;
        }
    }

}
